package com.yb.core.web.handler;

import com.yb.core.exception.message.XczxIllegalArgumentExceptionMessage;
import com.yb.core.enums.HttpCode;
import com.yb.core.model.XczxResult;
import com.yb.core.exception.XczxBusinessException;
import org.junit.platform.commons.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 全局统一异常处理
 * 主要针对本服务的接口中的异常
 * 对于跨服务的Feign调用异常
 * 调用的接口抛出异常，AbstractCommand#handleFallback
 * 函数是处理异常的函数,
 * 从方法后缀名可以得知,当exception是HystrixBadRequestException的时候是直接抛出的,
 * 不会触发fallback,也就意味着不会触发降级
 * 否则会直接触发fallback
 * 所以在本服务和Feign调用时业务都抛出HystrixBadRequestException
 */
@ControllerAdvice
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class GlobalExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(getClass());


    @Value("${spring.application.name:unknown}")
    private String appName;

//    private static final Set<String> EXCEPTION_NAME_SET =
//            Sets.newHashSet(
//                    "org.apache.catalina.connector.ClientAbortException",
//                    "org.springframework.web.client.HttpClientErrorException",
//                    "org.springframework.web.HttpMediaTypeNotAcceptableException",
//                    "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
//                    "org.springframework.web.HttpMediaTypeNotSupportedException",
//                    "org.springframework.web.bind.MissingServletRequestParameterException",
//                    "org.springframework.http.converter.HttpMessageNotReadableException",
//                    "org.springframework.web.HttpRequestMethodNotSupportedException",
//                    "org.springframework.security.access.AccessDeniedException",
//                    "org.springframework.web.multipart.MultipartException",
//                    "org.springframework.web.bind.MethodArgumentNotValidException"
//                    );

    /**
     * 全局异常
     *
     * @param e
     * @param response
     * @throws IOException
     */
    @ExceptionHandler(Exception.class)
    public void processException(Exception e, HttpServletResponse response) throws IOException {
//        sendWarningMessage(ex);
        logger.error(String.format("错误信息:%s",e.getMessage()), e);
        response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public @ResponseBody
    Object mismatchErrorHandler(HttpMessageNotReadableException e) {
        logger.error(String.format("错误信息:%s",e.getMessage()), e);
        return  XczxResult.error(HttpCode.Response.ERROR.getCode(), e.getMessage());
    }

    /**
     * 未知runtime异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public @ResponseBody
    Object processRuntimeException(RuntimeException ex) {
//        sendWarningMessage(ex);
        logger.error(String.format("错误信息:%s",ex.getMessage()), ex);

        if (StringUtils.isNotBlank(ex.getMessage())) {

            return XczxResult.error(HttpCode.Response.ERROR.getCode(),ex.getMessage());
        }
        return  XczxResult.error(HttpCode.Response.ERROR);
    }

    /**
     * 参数缺失错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public @ResponseBody
    Object processIllegalArgumentException(IllegalArgumentException ex) {
        logger.error(String.format("错误信息:%s",ex.getMessage()), ex);
        return  XczxResult.error(HttpCode.Response.ERROR.getCode(),ex.getMessage());
    }

    /**
     * 请求方式不支持错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public @ResponseBody
    Object processKkbBusinessException(HttpRequestMethodNotSupportedException ex) {
        logger.error(String.format("错误信息:%s",ex.getMessage()), ex);
        return  XczxResult.error(HttpCode.Response.ERROR.getCode(),ex.getMessage());
    }


    /**
     * 参数校验错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public @ResponseBody
    Object processParamValidateErrors(MethodArgumentNotValidException ex) {
        logger.error(String.format("错误信息:%s",ex.getMessage()), ex);
        List<XczxIllegalArgumentExceptionMessage> invalidArguments = new ArrayList<>();
        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            XczxIllegalArgumentExceptionMessage message = new XczxIllegalArgumentExceptionMessage();
            message.setDefaultMessage(error.getDefaultMessage());
            message.setField(error.getField());
            message.setRejectedValue(error.getRejectedValue());
            invalidArguments.add(message);
        }
        return  XczxResult.error(HttpCode.Response.ERROR, invalidArguments);
    }

    /**
     * 业务异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(XczxBusinessException.class)
    public @ResponseBody
    Object processKkbBusinessException(XczxBusinessException ex) {
        logger.error(String.format("错误信息:%s",ex.getMessage()), ex);
        return XczxResult.error(ex.getCode(), ex.getMessage());
    }


//    private void sendWarningMessage(Exception ex) {
//        logger.error("[ERROR] [" + appName + "] throw an exception ", ex);
//        DingtalkMessage message = new DingtalkMessage();
//        message.setText(TimeUtils.getTimestamp2DateStr(new Date(), null) + " - [" + appName + "] throw an exception : \n" + ExceptionUtils.getStackTrace(ex));
//        if (EXCEPTION_NAME_SET.contains(ex.getClass().getName())) {
//            return;
//        }
//        mqUtils.send(MessageQueue.Dingtalk.DINGTALK_QUEUE, message);
//    }


    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public @ResponseBody
    Object mismatchErrorHandler(MethodArgumentTypeMismatchException e) {
        logger.error(String.format("方法:%s,字段:%s,参数:%s,错误信息:%s", e.getParameter().getMethod(), e.getName(), e.getValue(), e.getMessage()), e);
        return  XczxResult.error(HttpCode.Response.ERROR.getCode(), e.getMessage());
    }


}
